package server;

import server.conf.*;
import server.conf.ServletWrapper;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author user
 */
public class RequestProcessor implements Runnable {

    private final Socket socket;
    private final Service service;

    public RequestProcessor(Socket socket, Service service) {
        this.socket = socket;
        this.service = service;
    }


    @Override
    public void run() {
        try {
            InputStream inputStream = socket.getInputStream();

            // 封装Request对象和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());
            String url = request.getUrl();
            url = this.formatUrl(url);
            Host host = this.findHost(url);
            if (host == null) {
                response.outputHtml(url);
            } else {
                Context context = this.findContext(host, url);
                if (context == null) {
                    response.outputHtml(url);
                } else {
                    Servlet servlet = this.findServlet(host, context, url);
                    if (servlet == null) {
                        //
                        String urlPrefix = this.removeUrlPrefix(host, context, url);
                        response.outputHtml(urlPrefix, context.getClassLoader());
                    } else {
                        // 动态资源servlet请求
                        servlet.service(request, response);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String formatUrl(String url) {
        return url.replace("//", "/");
    }


    /**
     * 删除请求 url 中的前缀上下文相关地址
     *
     * @param host    host
     * @param context context
     * @param url     请求url
     * @return 对应的servlet 的url
     */
    private String removeUrlPrefix(Host host, Context context, String url) {
        String cUrl = host.getHostUrl() + "/" + context.getUrl();
        cUrl = formatUrl(cUrl);
        return url.substring(cUrl.length());
    }

    /**
     * 在执行的 context 里面根据 url 匹配 servlet
     *
     * @param host    host
     * @param context context
     * @param url     请求 url
     * @return servlet
     */
    private Servlet findServlet(Host host, Context context, String url) {
        Map<String, ServletWrapper> servletMap = context.getServletMap();
        Map.Entry<String, ServletWrapper> entry = servletMap.entrySet().stream().filter(stringServletEntry -> {
            String cUrl = host.getHostUrl() + "/" + context.getUrl() + "/" + stringServletEntry.getKey();
            cUrl = formatUrl(cUrl);
            return url.startsWith(cUrl);
        }).findAny().orElse(null);
        if (entry == null) {
            return null;
        }
        return entry.getValue().getHttpServlet();
    }

    /**
     * 在指定的 host 里根据 url 匹配 context
     *
     * @param host host
     * @param url  请求 URL
     * @return Context
     */
    private Context findContext(Host host, String url) {
        List<Context> contexts = host.getContexts();
        return contexts.stream().filter(context -> {
            String cUrl = host.getHostUrl() + "/" + context.getUrl();
            cUrl = formatUrl(cUrl);
            return url.startsWith(cUrl);
        }).findAny().orElse(null);
    }

    /**
     * 根据 url 匹配到 host
     *
     * @param url 请求 url
     * @return host
     */
    private Host findHost(String url) {
        Mapper mapper = service.getMapper();
        List<Host> hosts = mapper.getHosts();
        Optional<Host> any = hosts.stream().filter(host -> {
            String hostUrl = host.getHostUrl();
            return url.startsWith(hostUrl);
        }).findAny();
        return any.orElse(null);
    }
}
